<!-- updated at 2022/04/11 -->
<template>
  <div class="zui-calendar">
    <div class="week">
      <span class="day" v-for="day in '一二三四五六日'" :key="day">
        {{ day }}
      </span>
    </div>
    <div class="dates">
      <div class="date-block" v-for="i in dayOffset" :key="i"></div>
      <div class="date-block" v-for="day in days" :key="day.num">
        <div
          class="date"
          :class="{ highlight: day.bottomText, today: isToday(day.date), exceeded: isExceeded(day.date) }"
          @click="onDateClick(day)"
        >
          <span class="date-num" :class="{ active: isCurDate(day.date) }">{{ day.text }}</span>
          <span v-if="day.bottomText" class="bottom-text"> {{ day.bottomText }}</span>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup>
import dateUtils from '@nmgolden/date-utils'
import { computed, ref, watch } from 'vue'

const emit = defineEmits(['dateClick', 'dateChange', 'update:curDate'])
const props = defineProps({
  monthDate: {
    type: Object,
    default: () => new Date()
  },
  curDate: {
    type: Object,
    default: () => new Date()
  },
  // 最小可选日期，默认60天前
  minDate: { type: Date, default: dateUtils.getDateByOffset(-60) },
  // 最大可选日期，默认今天
  maxDate: { type: Date, default: new Date() },
  formatter: Function
})

const curDate = ref()

const days = computed(() => {
  const lastDate = dateUtils.getLastDateOfMonth(props.monthDate)
  const amount = lastDate.getDate()

  // 构造日期数组
  const days = []
  for (let i = 0; ++i <= amount; ) {
    days.push({ date: getDateByDateNum(i), num: i, text: i.toString(), bottomText: '' })
  }

  // 调用外部格式化方法格式化日期数据
  if (props.formatter) {
    return days.map((item) => {
      return props.formatter(item)
    })
  } else {
    return days
  }

  function getDateByDateNum(dateNum) {
    const [year, month, day] = [props.monthDate.getFullYear(), props.monthDate.getMonth(), dateNum]
    return new Date(year, month, day)
  }
})

const dayOffset = computed(() => {
  const firstDate = dateUtils.getFirstDateOfMonth(props.monthDate)
  const firstDay = firstDate.getDay()
  return (firstDay - 1 + 7) % 7
})

watch(
  () => props.curDate,
  (value) => {
    curDate.value = value
  }
)

watch(curDate, (value) => {
  emit('dateChange', value)
  emit('update:curDate', value)
})

function isToday(date) {
  return dateUtils.isToday(date)
}

function isCurDate(date) {
  return dateUtils.isSameDate(curDate.value, date)
}

function isExceeded(date) {
  return date > props.maxDate || date < props.minDate
}

function onDateClick(day) {
  if (isExceeded(day.date)) {
    return
  }
  curDate.value = day.date
  emit('dateClick', day)
}
</script>

<style lang="scss" scoped>
.zui-calendar {
  .week {
    color: var(--zui-color-text-secondary);
    background: var(--zui-color-gray-light);
    padding: 4px 0;
    .day {
      display: inline-block;
      width: 14.28%;
      text-align: center;
    }
  }
  .dates {
    display: flex;
    flex-wrap: wrap;
    .date-block {
      display: block;
      width: 14.28%;
      min-height: 60px;
      padding: 8px 2px 0 2px;
      box-sizing: border-box;
      .date {
        display: flex;
        flex-direction: column;
        align-items: center;
        width: 100%;
        padding: 10px 0 10px 0px;

        &.highlight {
          border-top: 1px solid var(--zui-color-primary);
          background: rgba(var(--zui-color-primary-rgb), 0.08);
          padding-bottom: 4px;
          padding-top: 4px;
        }
        &.today {
          .date-num {
            color: var(--zui-color-primary);
            font-weight: bold;
          }
        }
        &.exceeded {
          .date-num {
            color: var(--zui-color-text-placeholder);
          }
        }
        .date-num {
          width: 24px;
          height: 24px;
          line-height: 24px;
          border-radius: 14px;
          text-align: center;
          &.active {
            background: var(--zui-color-primary);
            color: #ffffff;
            font-weight: bold;
          }
        }
        .bottom-text {
          font-size: var(--zui-size-text-xsmall);
          color: var(--zui-color-text-secondary);
          margin-top: 2px;
        }
      }
    }
  }
}
</style>
